#pragma once

#include <string>
#include <map>
#include <vector>
#include <variant>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/variance.hpp>

using namespace std;

namespace sample {
    struct Metric {
        enum Type {
            TypeUnknown = 0,
            TypeInt     = 1,
            TypeDouble  = 2,
            TypeString  = 5,
        };
        Type    type;   // 数据类型     
        string  name;   // 名字

        Metric(const string& n, Type t) : type(t), name(n) {}
        Metric(const string& n) : type(TypeString), name(n) {}

        bool operator<(const Metric& other) const {
            return name < other.name;
        }
    };
        
    typedef std::variant<int, double, std::string> DataType;
    typedef vector<DataType> ColumnData;
    typedef std::map<Metric, ColumnData> TableData;

    // 总体的表示
    class SampleFrame {
    public:
        void setData(const Metric& m, const ColumnData& d) { data_[m] = d; };

        void removeMetric(const string& name);
        /**整群处理， 总体分为i个群，然后从i个群中随机抽取若干个群，对这些群内所有个体或单元均进行调查
        * metricName   选择作为整群处理的指标
        * len          上述指标使用的位数 
        * metricMode    指标处理的方式  0：丢弃； 1：原值； 2：汇总
        * result        目前是处理后，产生一个数据集，添加了群标志和群内单位数两个字段
        */
        SampleFrame handleGroup(const string& metricName, unsigned len, const map<string, int>& metricMode);

        // 是否做了整群处理，实际上通过检查 群标志和群内单位数 也可以判断
        bool haveGrouped() const;

        
        unsigned getRowCount() const { return data_.empty() ? 0 : data_.begin()->second.size(); }

        /// @brief 计算指标的标准差  
        /// @param metricName 
        /// @return 
        double calculatePopulationStdDev(std::string& metricName);
        /// @brief  计算指标的方差
        /// @param metricName 
        /// @return 
        double calculatePopulationVariance(string& metricName);

        ColumnData* getColumn(const string& metricName) { 
            auto it = data_.find(metricName);
            if (it == data_.end()) {
                return nullptr;
            }
            return &(it->second);
        }
        
        Metric::Type getColumnType(const std::string& metricName) const;
        
        template<class T>
        std::vector<T> getColumnData(const std::string& metricName) const {
            std::vector<T> data;

            auto it = data_.find(metricName);
            if (it == data_.end()) {
                return data;
            }
            
            for(auto& m : it->second) {
                if (it->first.type == Metric::TypeInt) {
                    data.push_back(std::get<int>(m));
                }
                else if (it->first.type == Metric::TypeDouble) {
                    data.push_back(std::get<double>(m));
                }
                else if (it->first.type == Metric::TypeString) {
                    data.push_back(std::get<string>(m));
                }
            }

            return data;
        }

   protected:
        TableData  data_;            // 使用按列存储的方式，性能高； 每一列的长度应该都一样

        //std::string		GroupMetric_;	// 使用的指标名字
		//unsigned		GroupMetricSize_;	// 如果是字符型指标，可以指定使用从0开始的字符长度
    };

}
